Lists of commands

A list is a sequence of one or more pipelines separated by one of the operators ‘;’, ‘&’, ‘&&’, or ‘||’, and optionally terminated by one of ‘;’, ‘&’, or a newline.

Of these list operators, ‘&&’ and ‘||’ have equal precedence, followed by ‘;’ and ‘&’, which have equal precedence.

A sequence of one or more newlines may appear in a list to delimit commands, equivalent to a semicolon.

If a command is terminated by the control operator ‘&’, the shell executes the command asynchronously in a subshell. This is known as executing the command in the background, and these are referred to as asynchronous commands. The shell does not wait for the command to finish, and the return status is 0 (true). When job control is not active (see Job Control), the standard input for asynchronous commands, in the absence of any explicit redirections, is redirected from /dev/null.

Commands separated by a ‘;’ are executed sequentially; the shell waits for each command to terminate in turn. The return status is the exit status of the last command executed.

AND and OR lists are sequences of one or more pipelines separated by the control operators ‘&&’ and ‘||’, respectively. AND and OR lists are executed with left associativity.

Special parameters

The shell treats several parameters specially. These parameters may only be referenced; assignment to them is not allowed.

($) Expands to the positional parameters, starting from one. When the expansion is not within double quotes, each positional parameter expands to a separate word. In contexts where it is performed, those words are subject to further word splitting and filename expansion. When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable. That is, "$" is equivalent to "$1c$2c…", where c is the first character of the value of the IFS variable. If IFS is unset, the parameters are separated by spaces. If IFS is null, the parameters are joined without intervening separators.

($@) Expands to the positional parameters, starting from one. In contexts where word splitting is performed, this expands each positional parameter to a separate word; if not within double quotes, these words are subject to word splitting. In contexts where word splitting is not performed, this expands to a single word with each positional parameter separated by a space. When the expansion occurs within double quotes, and word splitting is performed, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" …. If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed).

($#) Expands to the number of positional parameters in decimal.

($?) Expands to the exit status of the most recently executed foreground pipeline.

($-, a hyphen.) Expands to the current option flags as specified upon invocation, by the set builtin command, or those set by the shell itself (such as the -i option).

($$) Expands to the process ID of the shell. In a subshell, it expands to the process ID of the invoking shell, not the subshell.

($!) Expands to the process ID of the job most recently placed into the background, whether executed as an asynchronous command or using the bg builtin (see Job Control Builtins).

($0) Expands to the name of the shell or shell script. This is set at shell initialization. If Bash is invoked with a file of commands (see Shell Scripts), $0 is set to the name of that file. If Bash is started with the -c option (see Invoking Bash), then $0 is set to the first argument after the string to be executed, if one is present. Otherwise, it is set to the filename used to invoke Bash, as given by argument zero.

Redirection

/dev/fd/0 = /dev/stdin
/dev/fd/1 = /dev/stdout
/dev/fd/2 = /dev/stderr

Note: in this document, fd is abbr. of file description or I/O object.

Output redirection: [n]>[|]word. Here [n] is a standard fd. If [n] is ommited, then 1(stdout) is assigned. Expansion of word should be an I/O object.

Appending output redirection: [n]>>word. Here [n] is a standard fd. If [n] is ommited, then 1(stdout) is assigned. Expansion of word should be an I/O object.

Input redirection: [n]<word. Here [n] is a standard fd. If [n] is ommited, then 0(stdin) is assigned. Expansion of word should be an I/O ojbect.

Input redirection redirects data of an I/O object to stdin of a program as args.

Output redirection redirects stdout/stderr of a program to an I/O object.

Pipelines

In cmd1 |[&] cmd2, the output of each command in the pipeline is connected via a pipe to the input of the next command.

If the pipeline is not executed asynchronously (see Lists of Commands), the shell waits for all commands in the pipeline to complete.

Each command in a multi-command pipeline, where pipes are created, is executed in its own subshell, which is a separate process (see Command Execution Environment).

Process Substitution

Process substitution allows a process’s input or output to be referred to using a filename. It takes the form of

<(list)

or

>(list)

The process list is run asynchronously, and its input or output appears as a filename (/dev/fd/63). This filename is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list. Note that no space may appear between the < or > and the left parenthesis, otherwise the construct would be interpreted as a redirection. Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files.

When available, process substitution is performed simultaneously with parameter and variable expansion, command substitution, and arithmetic expansion.

sudo

sudo has more restictions than regular execuction env due to security design.

It is executed as root user instead current user, so its env is root related. Files permissions are root related.

Its env is more limited and current user's env is not passed to sudo process by default. To pass variables or env varialbes to sudo, use sudo PAHT=$PATH ... or sudo --perserve-env=list ....

/dev/fd/n higher than 2 is closed in sudo mode. Process substitution may fail due to this.

bash -c may be used if pipeline fails.

But explict pipelien or named piple could be more useful in a command chain with sudo cmd involed.

cmd1 | sudo cmd2 --opt /dev/stdin

or

named_pipe=mkfifo -m 600 $(uuid)
cmd1 >named_pipe &
sudo cmd2 --opt named_pipe
rm named_pipe

Published

Category

Linux

Tags

Contact